﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;

namespace Input
{
    public class GameInput
    {
        private List<MouseInputListener> MouseListeners;
        private List<KeyboardInputListener> KeyboardListeners;

        private KeyboardState OldKeyboardState;
        private KeyboardState CurrentKeyboardState;

        private MouseState OldMouseState;
        private MouseState CurrentMouseState;

        public GameInput()
        {
            MouseListeners = new List<MouseInputListener>();
            KeyboardListeners = new List<KeyboardInputListener>();
        }

        public void AddKeyboardListener(KeyboardInputListener Listener)
        {
            KeyboardListeners.Add(Listener);
            Listener.OnKeyboardRegister(this);
        }

        public void AddMouseListener(MouseInputListener Listener)
        {
            MouseListeners.Add(Listener);
            Listener.OnMouseRegister(this);
        }

        public void Update()
        {
            UpdateCurrentStates();

            foreach (MouseInputListener MouseListener in MouseListeners)
            {
                MouseListener.UpdateMouseInput(this);
            }

            foreach (KeyboardInputListener KeyboardListener in KeyboardListeners)
            {
                KeyboardListener.UpdateKeyboardInput(this);
            }

            UpdateOldStates();
        }

        /**
         * This returns if the key is pressed.  This returns true if
         * it is down now and wasn't down before.
         * */
        public bool IsKeyPressed(Keys key)
        {
            if (!CurrentKeyboardState.IsKeyDown(key))
                return false;
            else
            {
                if (OldKeyboardState != null)
                    return OldKeyboardState.IsKeyUp(key);
                else
                    return true;
            }
        }

        /**
         * This returns whether or not the key is down.  Note that this is
         * different than the key being pressed.
         * */
        public bool IsKeyDown(Keys key)
        {
            return CurrentKeyboardState.IsKeyDown(key);
        }

        public bool IsLeftMouseButtonDown()
        {
            return (CurrentMouseState.LeftButton == ButtonState.Pressed);
        }

        public bool IsRightMouseButtonDown()
        {
            return (CurrentMouseState.RightButton == ButtonState.Pressed);
        }

        public bool IsLeftMouseButtonPressed()
        {
            if (CurrentMouseState.LeftButton != ButtonState.Pressed)
                return false;
            else
            {
                if (OldMouseState != null)
                    return OldMouseState.LeftButton == ButtonState.Released;
                else
                    return true;
            }
        }

        public Vector2 GetMousePosition()
        {
            return new Vector2(CurrentMouseState.X, CurrentMouseState.Y);
        }

        public bool IsRightMouseButtonPressed()
        {
            if (CurrentMouseState.RightButton != ButtonState.Pressed)
                return false;
            else
            {
                if (OldMouseState != null)
                    return OldMouseState.RightButton == ButtonState.Released;
                else
                    return true;
            }
        }

        /**
         * This method returns whether or not the mouse is within a specified
         * rectangle.  This uses a simple axis of separation test.
         */
        public bool IsMouseInRectangle(Rectangle rect)
        {
            Vector2 mousePos = GetMousePosition();
            bool horizontalCollision = (mousePos.X >= rect.Left) && (mousePos.X <= rect.Right);
            bool verticalCollision = (mousePos.Y >= rect.Top) && (mousePos.Y <= rect.Bottom);

            return horizontalCollision && verticalCollision;
        }
        
        /**
         * This method returns whether or not the mouse is within a specified
         * rectangle that may be rotated.  It rotations the mouse clockwise
         * to be within the same rotation angle as the rectangle.  Then it 
         * does a simple separating axis check.
         */
        public bool IsMouseInRectangle(Rectangle rect, float rotation)
        {
            Vector2 mousePos = GetMousePosition();
            mousePos.X = mousePos.X - rect.Center.X;
            mousePos.Y = mousePos.Y - rect.Center.Y;

            float rotationPrime = rotation;

            double xPrime = (mousePos.X * Math.Cos(rotationPrime) + mousePos.Y * Math.Sin(rotationPrime));
            double yPrime = (-mousePos.X * Math.Sin(rotationPrime) + mousePos.Y * Math.Cos(rotationPrime));

            xPrime = xPrime + rect.Center.X;
            yPrime = yPrime + rect.Center.Y;

            bool horizontalCollision = (xPrime >= rect.Left) && (xPrime <= rect.Right);
            bool verticalCollision = (yPrime >= rect.Top) && (yPrime <= rect.Bottom);

            return horizontalCollision && verticalCollision;
        }

        private void UpdateCurrentStates()
        {
            CurrentKeyboardState = Keyboard.GetState();
            CurrentMouseState = Mouse.GetState();
        }

        private void UpdateOldStates()
        {
            OldKeyboardState = CurrentKeyboardState;
            OldMouseState = CurrentMouseState;
        }
    }
}
